<template>
  <div
    :class="animate"
    :style="{ height: height, width: width }"
    :id="chartOption.bindingDiv"
    ref="chartDiv"
  ></div>
</template>

<script>
import echarts from "echarts";
require("echarts/theme/macarons"); // echarts theme
import resize from "@/views/dashboard/mixins/resize";

import "../../animate/animate.css";

import { parseQueryString, fIsUrL } from "../../util/urlUtil";
import { chartApiBar, remoteChartApi } from "@/api/tool/datav/chartApi";
import { websocketCommand } from "../../util/websocket.js";
import { addOption } from "../../codegen/codegen";

const animationDuration = 6000;

export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: "chart"
    },
    width: {
      type: String,
      default: "100%"
    },
    height: {
      type: String,
      default: "100%"
    },
    chartOption: {
      type: Object
    },
    customId: {
      type: Number
    },
    drawingList: {
      type: Array
    }
  },
  data() {
    return {
      chart: null,
      //dataOption: this.chartOption
      value: "",
      timer: "",
      wsObj: null,
      wsFlag: false,
      wsTimer: "",
      wsValue: null,
      animate: this.className
    };
  },
  watch: {
    width() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    height() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    chartOption: {
      deep: true,
      handler(newVal) {
        this.setOptions(JSON.parse(JSON.stringify(newVal)));
      }
    },
    "chartOption.timeout": {
      handler() {
        this.chart = null;
        this.initChart();
      }
    },
    "chartOption.dataSourceType": {
      handler(value) {
        //切换数据源重新连接
        if (value !== "websocket") {
          this.wsFlag = false;
          //每次切换数据源恢复原来动画
          this.animate = this.className;
        }
        if (value !== "url") {
          clearTimeout(this.timer);
        } 
      }
    },
    "chartOption.interfaceKey": {
      handler(newValue, oldValue) {
        //初始化不创建连接，改变接口地址重新创建
        if (oldValue !== undefined && oldValue != "") {
          this.wsValue = null;
          this.closeWs();
          this.createWs();
          this.animate = this.className;
        }
      }
    },
    wsFlag: {
      handler(value) {
        if (!value) {
          this.wsValue = null;
          this.closeWs();
        }
      }
    },
    className: {
      handler(value) {
        this.animate = value;
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart();
    });
  },
  beforeDestroy() {
    if (!this.chart) {
      return;
    }
    this.chart.dispose();
    this.chart = null;
    clearTimeout(this.timer);
    if (this.wsFlag) {
      this.closeWs();
    }
  },
  computed: {},
  methods: {
    initChart() {
      this.chart = echarts.init(this.$el, "macarons");
      
      //判断是否开启定时器，当是访问url接口时候并且timeout不为0时候开启定时器
      if (this.timer != "") {
        clearTimeout(this.timer);
      }
      if (
        (this.chartOption.dataSourceType == 'url' || this.chartOption.dataSourceType == 'database') &&
        this.chartOption.timeout > 0
      ) {
        let timerTask = () => {
          this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
          this.timer = setTimeout(() => {
           
            timerTask();
          }, this.chartOption.timeout);
        };

        timerTask();
      }else{
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    setOptions: async function(dataOption) {
      //初始化数据
      //如果不是静态数据就调用接口给staticDataValue赋值
      if (dataOption.dataSourceType == "url" || dataOption.isStaticData == false) {
        let paramJson = parseQueryString(dataOption.requestParameters);

        let interfaceURL = dataOption.interfaceURL;

        let result = await chartApiBar(
          dataOption.requestMethod,
          interfaceURL,
          paramJson,
          dataOption.token
        );
        dataOption.staticDataValue = result;

      } else if (dataOption.dataSourceType == "database") {
      } else if (dataOption.dataSourceType == "websocket") {
        if (
          dataOption.interfaceKey != undefined &&
          dataOption.interfaceKey != ""
        ) {
          if (!this.wsFlag) {
            this.wsFlag = true;
            this.wsValue = null;
            this.createWs();
          }
          if (this.wsValue != null) {
            dataOption.staticDataValue = this.wsValue;
          }
        }
      }

      let option = {
        baseOption: {
          timeline: {
            left: "10%",
            right: "10%",
            top: "40%",
            width: "80%",
            axisType: "category",
            // realtime: false,
            // loop: false,
            autoPlay: dataOption.autoPlay,
            // currentIndex: 2,
            playInterval: dataOption.playInterval,
            data: dataOption.staticDataValue,

            label: {
              normal: {
                textStyle: {
                  color: dataOption.fontColor,
                  fontSize: dataOption.fontSize
                },
                formatter: function(s) {
                  return s + dataOption.suffix;
                }
              },
              emphasis: {
                textStyle: {
                  color: dataOption.checkFontColor
                }
              }
            },
            symbolSize: dataOption.symbolSize, //圆点大小
            lineStyle: {
              color: dataOption.lineColor //线颜色
            },
            itemStyle: {
              emphasis: {
                color: dataOption.pointColor
              }
            },
            checkpointStyle: {
              color: dataOption.checkPointColor,
              borderColor: dataOption.borderColor, //选中圆点边框颜色
              borderWidth: dataOption.borderWidth //选中圆点边框宽度
            },
            controlStyle: {
              showNextBtn: dataOption.showNextBtn, //下一个按钮
              showPrevBtn: dataOption.showPrevBtn, //上一个按钮
              showPlayBtn: dataOption.showPlayBtn,
              normal: {
                color: dataOption.buttonColor,
                borderColor: dataOption.buttonColor
              },
              emphasis: {
                color: dataOption.checkButtonColor,
                borderColor: dataOption.checkButtonColor
              }
            }
          }
        }
      };
     
      //执行通用处理函数
      if(dataOption.customData != undefined && dataOption.customData != ""){
        try {
          option = (
          
            //里面为要处理的代码块
          eval(dataOption.customData) 
          
          )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
          );
        } catch (error) {
          console.log(error)
        }
       } 
        //交互组件配置
      if(dataOption.interactData != undefined && dataOption.interactData != ""){
          try {
              option = (        
              //里面为要处理的代码块
              eval(dataOption.interactData)             
            )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
            );
          } catch (error) {
            console.log(error)
          }               
       }
      
      this.chart.clear();
      this.chart.setOption(option, true);

      let drawingList = this.drawingList;

      if(this.chart != undefined){
        //监听切换数据
        let that = this;
        that.chart.on("timelinechanged", function(timeLineIndex) {
          let val = dataOption.staticDataValue[timeLineIndex.currentIndex];
          //获取绑定的图表，传递参数，重新渲染
          let bindList = dataOption.bindList;
          let name = dataOption.aggrName;
  
          if (bindList != null && bindList.length > 0) {
            let exclusion = [
              "input",
              "timeframe",
              "select",
              "cascade",
              "tab",
              "textCheckBox",
              "timeline",
              "group"
            ];
            let renderCharts = drawingList.filter(item => {
              return (
                bindList.indexOf(item.customId) > -1 &&
                exclusion.indexOf(item.type) == -1
              );
            });
            //遍历绑定组件
            renderCharts.forEach(item => {
              //获取组件参数
              let requestParameters = item.chartOption.requestParameters;
  
              //如果已经包含该名称的参数则替换
              if (
                requestParameters != "" &&
                requestParameters.indexOf(name) != -1
              ) {
                //拆分成数组
                let paramArr = requestParameters.split("&");
                if (paramArr.length > 1) {
                  paramArr.pop();
                }
                //获取到包含该名称的数组项
                for (let i in paramArr) {
                  if (paramArr[i].indexOf(name) != -1) {
                    //替换位=为
                    当前内容;
                    paramArr.splice(i, 1, name + "=" + val);
                  }
                }
                //将数组重新按照&符号拼接为字符串
                requestParameters = "&" + paramArr.join("&");
              } else {
                if (requestParameters != "") {
                  let paramArr = requestParameters.split("&");
                  if (paramArr.length > 1) {
                    paramArr.pop();
                  }
                  requestParameters = "&" + paramArr.join("&");
                }
                //如果为新名称参数直接拼在结尾
                requestParameters += "&" + name + "=" + val;
              }
              //判断参数是否已&符号开始，是则删除该符号
              if (requestParameters.indexOf("&") == 0) {
                item.chartOption.requestParameters =
                  requestParameters.substring(1, requestParameters.length) +
                  "&timestamp=" +
                  new Date().getTime();
              } else {
                //给绑定组件重新赋值参数渲染组件
                item.chartOption.requestParameters =
                  requestParameters + "&timestamp=" + new Date().getTime();
              }
            });
          }
          //远程控制组件
          if (dataOption.isRemote == true) {
            if (dataOption.remote != undefined && dataOption.remote != null) {
              let remoteData = { ...dataOption.remote };
              let queryObj = {};
              queryObj[name] = val;
              remoteData.query = queryObj;
              //调用接口
              remoteChartApi(remoteData);
            }
          }
          that.chart.off("timelinechanged");
        });
      }

      addOption(dataOption.bindingDiv, option);
    },
    //  ws连接成功，后台返回的ws数据
    receiveMsg(e) {
      if (e.action == "chat") {
        // console.log('服务端推送',e);
        this.wsValue = e.result;
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    // 建立连接、发起ws请求，以心跳方式，向服务端发送数据
    createWs() {
      this.wsObj = new WebSocket(process.env.VUE_APP_WEBSOCKET);
      // 若为对象类型，以回调方式发送
      websocketCommand(
        this.wsObj,
        "create",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
    },
    // 断网重连，需要处理的逻辑
    reconnectWs() {
      if (this.wsObj) {
        console.log("%c websocket_reconnect", "color:blue");
        this.createWs();
      }
    },
    // 以回调方式向服务端发送(对象类型的)心跳
    sendHeartBeat() {
      if (this.wsTimer != "") {
        clearTimeout(this.wsTimer);
      }

      let wsTimerTask = () => {
        console.log("发送心跳", "ping");
        let obj = { action: "keep", key: this.chartOption.interfaceKey };
        this.wsObj.send(JSON.stringify(obj));
        this.wsTimer = setTimeout(() => {
          wsTimerTask();
        }, parseInt(process.env.VUE_APP_WEBSOCKET_TIMEOUT));
        this.wsWarning();
      };

      wsTimerTask();
    },
    wsWarning() {
      //如果断开连接则显示组件警告动画并清除计数器
      if (this.wsObj.readyState == 3) {
        this.animate = "warning";
        clearTimeout(this.wsTimer);
      }
    },
    closeWs() {
      clearTimeout(this.wsTimer);
      websocketCommand(
        this.wsObj,
        "close",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
      this.wsObj = null;
    }
  }
};
</script>
